home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / MacPerl 5.1.3 / Mac_Perl_513_src / MacPerl5 / MPSave.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-18  |  19.3 KB  |  1,008 lines  |  [TEXT/MPS ]

  1. /*********************************************************************
  2. Project    :    MacPerl            -    Real Perl Application
  3. File        :    MPSave.c            -    Handle all the runtimes
  4. Author    :    Matthias Neeracher
  5.  
  6. A lot of this code is borrowed from 7Edit written by
  7. Apple Developer Support UK
  8.  
  9. Language    :    MPW C
  10.  
  11. $Log: MPSave.c,v $
  12. Revision 1.1  1994/02/27  23:01:45  neeri
  13. Initial revision
  14.  
  15. Revision 0.1  1993/10/03  00:00:00  neeri
  16. Compiles correctly
  17.  
  18. *********************************************************************/
  19.  
  20. #include <Errors.h>
  21. #include <Resources.h>
  22. #include <PLStringFuncs.h>
  23. #include <LowMem.h>
  24. #include <Folders.h>
  25. #include <Finder.h>
  26. #include <TFileSpec.h>
  27.  
  28. #include <string.h>
  29.  
  30. #include "MPSave.h"
  31. #include "MPGlobals.h"
  32. #include "MPFile.h"
  33. #include "MPUtils.h"
  34.  
  35. #if defined(powerc) || defined (__powerc)
  36. #pragma options align=mac68k
  37. #endif
  38.  
  39. #define SERsrcBase    32700
  40.  
  41. typedef struct {
  42.     OSType            version; 
  43.     OSType            id;
  44.     OSType            fType;
  45.     OSType            fCreator;
  46.     
  47.     unsigned            wantsBundle     : 1;
  48.     unsigned            hasCustomIcon     : 1;
  49. } SEPackage, ** SEPackageHdl;
  50.  
  51. typedef struct {
  52.     OSType    type;
  53.     OSType    realType;
  54.     short        id;
  55.     short        realID;
  56. } ShoppingList, ** ShoppingListHdl;
  57.  
  58. typedef struct {
  59.     OSType    type;
  60.     short        id;
  61. } OwnerList;
  62.  
  63. #if defined(powerc) || defined (__powerc)
  64. #pragma options align=reset
  65. #endif
  66.  
  67. typedef struct {
  68.     OSType            id;
  69.     OSType            fType;
  70.     OSType            fCreator;
  71.     StringHandle    name;
  72.     Boolean            wantsBundle;
  73.     Boolean            hasCustomIcon;
  74.     FSSpec            file;
  75. } SaveExtension;
  76.  
  77. typedef struct {
  78.     short                count;
  79.     SaveExtension    ext[1];
  80. } SERec, * SEPtr, ** SEHdl;
  81.  
  82. SEHdl            SaveExtensions    =    nil;
  83. OSType **    FileTypeH = nil;
  84. OSType *     MacPerlFileTypes;
  85. short            MacPerlFileTypeCount;
  86.  
  87. OwnerList noOwner[] = {
  88.     0, 0
  89. };
  90.  
  91. OwnerList ancientOwner[] = {
  92.     'ALRT', 256,
  93.     'ALRT', 257,
  94.     'ALRT', 262,
  95.     'ALRT', 266,
  96.     'ALRT', 270,
  97.     'ALRT', 274,
  98.     'ALRT', 300,
  99.     'ALRT', 302,
  100.     'ALRT', 3850,
  101.     'BNDL', 128,
  102.     'CNTL', 192,
  103.     'CODE', 0,
  104.     'CODE', 1,
  105.     'CODE', 2,
  106.     'CODE', 3,
  107.     'CODE', 4,
  108.     'CODE', 5,
  109.     'CODE', 6,
  110.     'CODE', 7,
  111.     'CODE', 8,
  112.     'CODE', 9,
  113.     'CODE', 10,
  114.     'CODE', 11,
  115.     'CODE', 12,
  116.     'CODE', 13,
  117.     'CODE', 14,
  118.     'CODE', 15,
  119.     'CODE', 16,
  120.     'CODE', 17,
  121.     'CODE', 18,
  122.     'CODE', 19,
  123.     'CODE', 20,
  124.     'CODE', 21,
  125.     'CODE', 22,
  126.     'CODE', 23,
  127.     'CODE', 24,
  128.     'CODE', 25,
  129.     'CODE', 26,
  130.     'CODE', 27,
  131.     'CODE', 28,
  132.     'CODE', 29,
  133.     'CODE', 30,
  134.     'CODE', 31,
  135.     'CODE', 32,
  136.     'CODE', 33,
  137.     'CODE', 34,
  138.     'CODE', 35,
  139.     'CODE', 36,
  140.     'CODE', 37,
  141.     'CODE', 38,
  142.     'CODE', 39,
  143.     'CODE', 40,
  144.     'CODE', 41,
  145.     'CODE', 42,
  146.     'CODE', 43,
  147.     'CODE', 44,
  148.     'CODE', 45,
  149.     'CODE', 46,
  150.     'CODE', 47,
  151.     'CODE', 48,
  152.     'CODE', 49,
  153.     'CODE', 50,
  154.     'CODE', 51,
  155.     'CURS', 128,
  156.     'CURS', 129,
  157.     'CURS', 130,
  158.     'CURS', 131,
  159.     'CURS', 132,
  160.     'CURS', 144,
  161.     'CURS', 145,
  162.     'CURS', 146,
  163.     'CURS', 147,
  164.     'CURS', 148,
  165.     'CURS', 160,
  166.     'CURS', 161,
  167.     'CURS', 162,
  168.     'CURS', 163,
  169.     'DITL', 192,
  170.     'DITL', 256,
  171.     'DITL', 257,
  172.     'DITL', 258,
  173.     'DITL', 262,
  174.     'DITL', 266,
  175.     'DITL', 270,
  176.     'DITL', 274,
  177.     'DITL', 300,
  178.     'DITL', 302,
  179.     'DITL', 320,
  180.     'DITL', 384,
  181.     'DITL', 385,
  182.     'DITL', 386,
  183.     'DITL', 387,
  184.     'DITL', 512,
  185.     'DITL', 1005,
  186.     'DITL', 2001,
  187.     'DITL', 2002,
  188.     'DITL', 2003,
  189.     'DITL', 2010,
  190.     'DITL', 2020,
  191.     'DITL', 3850,
  192.     'DITL', 10240,
  193.     'DLOG', 192,
  194.     'DLOG', 258,
  195.     'DLOG', 320,
  196.     'DLOG', 384,
  197.     'DLOG', 512,
  198.     'DLOG', 1005,
  199.     'DLOG', 2001,
  200.     'DLOG', 2002,
  201.     'DLOG', 2003,
  202.     'DLOG', 2010,
  203.     'DLOG', 2020,
  204.     'DLOG', 10240,
  205.     'FOND', 19999,
  206.     'FOND', 32268,
  207.     'FREF', 128,
  208.     'FREF', 129,
  209.     'FREF', 130,
  210.     'FREF', 131,
  211.     'FREF', 132,
  212.     'FREF', 133,
  213.     'FREF', 134,
  214.     'GU∑I', 10240,
  215.     'ICN#', 10240,
  216.     'ICN#', 128,
  217.     'ICN#', 129,
  218.     'ICN#', 130,
  219.     'ICN#', 131,
  220.     'ICN#', 385,
  221.     'ICN#', 386,
  222.     'ICN#', 387,
  223.     'IRng', 128,
  224.     'LDEF', 128,
  225.     'MDEF', 1,
  226.     'MENU', 128,
  227.     'MENU', 129,
  228.     'MENU', 130,
  229.     'MENU', 131,
  230.     'MENU', 132,
  231.     'MENU', 192,
  232.     'McPL', 0,
  233.     'MrP#', 128,
  234.     'MrP4', 128,
  235.     'MrP8', 128,
  236.     'MrPA', 4096,
  237.     'MrPB', 128,
  238.     'MrPC', 0,
  239.     'MrPC', 1,
  240.     'MrPC', 2,
  241.     'MrPD', 4096,
  242.     'MrPF', 132,
  243.     'MrPF', 133,
  244.     'MrPF', 134,
  245.     'MrPI', 128,
  246.     'MrPL', 0,
  247.     'MrPS', -1,
  248.     'NFNT', 2816,
  249.     'NFNT', 2825,
  250.     'NFNT', 2828,
  251.     'NFNT', 32268,
  252.     'PICT', 128,
  253.     'SIZE', -1,
  254.     'STR ', 133,
  255.     'STR#', 129,
  256.     'STR#', 130,
  257.     'STR#', 132,
  258.     'STR#', 256,
  259.     'STR#', 32268,
  260.     'STR#', 384,
  261.     'TMPL', 10240,
  262.     'WIND', 128,
  263.     'WIND', 129,
  264.     'WIND', 130,
  265.     'acur', 0,
  266.     'acur', 128,
  267.     'acur', 129,
  268.     'aete', 0,
  269.     'dctb', 384,
  270.     'hmnu', 129,
  271.     'hmnu', 130,
  272.     'hmnu', 132,
  273.     'icl4', 128,
  274.     'icl4', 129,
  275.     'icl4', 130,
  276.     'icl4', 131,
  277.     'icl4', 385,
  278.     'icl4', 386,
  279.     'icl4', 387,
  280.     'icl8', 128,
  281.     'icl8', 129,
  282.     'icl8', 130,
  283.     'icl8', 131,
  284.     'icl8', 385,
  285.     'icl8', 386,
  286.     'icl8', 387,
  287.     'icm#', 256,
  288.     'icm#', 257,
  289.     'icm#', 264,
  290.     'icm#', 265,
  291.     'icm#', 266,
  292.     'ics#', 128,
  293.     'vers', 1,
  294.     'vers', 2,
  295.     0,      0
  296. };
  297.  
  298. OwnerList * noOwnerPtr = noOwner;
  299. OwnerList * ancientOwnerPtr = ancientOwner;
  300.  
  301. Boolean InOwnerList(OSType type, short id, OwnerList * list)
  302. {
  303.     while (list->type)
  304.         if (list->type == type && list->id == id)
  305.             return true;
  306.         else
  307.             ++list;
  308.     
  309.     return false;
  310. }
  311.  
  312. OSErr CopySomeResources(short origFile, short resFile)
  313. {
  314.     OSErr                err;
  315.     Handle             rsrc;
  316.     Handle            nur;
  317.     short                typeCnt;
  318.     short                typeIdx;
  319.     short                rsrcCnt;
  320.     short                rsrcIdx;
  321.     short                rsrcID;
  322.     Boolean            wantItBadly;
  323.     ResType            rsrcType;
  324.     Str255            rsrcName;
  325.     OwnerList **    include;
  326.     OwnerList **    exclude;
  327.     
  328.     UseResFile(origFile);
  329.     
  330.     if (!(exclude = (OwnerList **) Get1Resource('McPo', 128)))
  331.         exclude = &ancientOwnerPtr;
  332.  
  333.     if (!(include = (OwnerList **) Get1Resource('McPo', 129)))
  334.         include = &noOwnerPtr;
  335.     
  336.     typeCnt = Count1Types();
  337.     
  338.     for (typeIdx = 0; typeIdx++ < typeCnt; ) {
  339.         Get1IndType(&rsrcType, typeIdx);
  340.         
  341.         rsrcCnt = Count1Resources(rsrcType);
  342.         
  343.         for (rsrcIdx = 0; rsrcIdx++ < rsrcCnt; ) {
  344.             rsrc = Get1IndResource(rsrcType, rsrcIdx);
  345.             
  346.             if (!rsrc) 
  347.                 return ResError();
  348.             
  349.             GetResInfo(rsrc, &rsrcID, &rsrcType, rsrcName);
  350.             
  351.             if (rsrcType == 'McPo' && rsrcID == 128)
  352.                 continue;
  353.             if (rsrcType == 'TEXT' && !PLstrcmp(rsrcName, "\p!"))
  354.                 continue;
  355.             if (rsrcType == 'McPo' && rsrcID == 129) {
  356.                 wantItBadly = true;
  357.                 HandToHand(&rsrc);
  358.             } else {
  359.                 wantItBadly = InOwnerList(rsrcType, rsrcID, *include);
  360.                 DetachResource(rsrc);
  361.             }
  362.             
  363.             if (wantItBadly || !InOwnerList(rsrcType, rsrcID, *exclude)) {
  364.                 UseResFile(resFile);
  365.         
  366.                 if (nur = Get1Resource(rsrcType, rsrcID))
  367.                     if (wantItBadly) {
  368.                         RmveResource(nur);
  369.                         
  370.                         nur = nil;
  371.                     }
  372.                 
  373.                 if (!nur) {    
  374.                     AddResource(rsrc, rsrcType, rsrcID, rsrcName);
  375.                 
  376.                     if (err = ResError()) {
  377.                         DisposeHandle(rsrc);
  378.                         return err;
  379.                     }
  380.                 } else 
  381.                     DisposeHandle(rsrc);
  382.                 
  383.                 UseResFile(origFile);
  384.             } else
  385.                 DisposeHandle(rsrc);
  386.         }
  387.     }
  388.     
  389.     return noErr;
  390. }
  391.  
  392. OSErr    CopyShoppingList(short from, short to, ShoppingList * list, StringPtr fileName)
  393. {
  394.     OSErr            err;
  395.     
  396.     for (; list->type; ++list) {
  397.         Handle        rsrc;
  398.         Handle        nur;
  399.         Str255        name;
  400.         char *        macro;
  401.         char *      end;
  402.         int            len;
  403.                 
  404.         UseResFile(from);
  405.         
  406.         rsrc = Get1Resource(list->type, list->id);
  407.         
  408.         if (!rsrc)
  409.             return ResError();
  410.         
  411.         UseResFile(to);
  412.         
  413.         GetResInfo(rsrc, &list->id, &list->type, name);
  414.         name[name[0]+1] = 0;
  415.         
  416.         for (macro = strchr((char *)name+1, '%'); macro; )
  417.             if (macro[1] == 'n') {
  418.                 if (end = (char *)memchr(fileName+1, '.', *name)) 
  419.                     len = end - (char *) fileName - 1;
  420.                 else
  421.                     len = *fileName;
  422.                 memmove(macro+len, macro+2, strlen(macro+2)+1);
  423.                 memcpy(macro, fileName+1, len);
  424.                 macro += len;
  425.             } else
  426.                 macro = strchr(macro+1, '%');
  427.             
  428.         name[0] = strlen((char *)name+1);
  429.         if (nur = Get1Resource(list->realType, list->realID))
  430.             RmveResource(nur);
  431.             
  432.         HandToHand(&rsrc);
  433.         AddResource(rsrc, list->realType, list->realID, name);
  434.         
  435.         if (err = ResError())
  436.             goto finish;
  437.         
  438. nextrsrc:
  439.         ;
  440.     }
  441.     
  442. finish:
  443.     UseResFile(from);
  444.     
  445.     return err;
  446. }
  447.  
  448. #if !defined(powerc) && !defined(__powerc)
  449. #pragma segment File
  450. #endif
  451.  
  452. static OSType    WantsType;
  453. static OSType    WantsCreator;
  454. static Boolean    WantsBundle;
  455. static Boolean    HasCustomIcon;
  456.  
  457. OSErr DoOpenResFile(FSSpec * spec, short * resFile)
  458. {
  459.     OSErr    err;
  460.     FInfo info;
  461.     
  462.     *resFile = HOpenResFile(spec->vRefNum, spec->parID, spec->name, fsRdWrPerm);
  463.     if (*resFile == -1) {
  464.         if (err = DoCreate(*spec))
  465.             return err;
  466.  
  467.         *resFile =  HOpenResFile(spec->vRefNum, spec->parID, spec->name, fsRdWrPerm);
  468.         if (*resFile == -1) {
  469.             FileError((StringPtr) "\perror opening file ", spec->name);
  470.             
  471.             return ResError();
  472.         }
  473.     }
  474.     
  475.     HGetFInfo(spec->vRefNum, spec->parID, spec->name, &info);
  476.     
  477.     info.fdType        =    WantsType;
  478.     info.fdCreator    =    WantsCreator;
  479.     
  480.     if (WantsBundle)
  481.         info.fdFlags     |= kHasBundle;
  482.     if (HasCustomIcon)
  483.         info.fdFlags     |= kHasCustomIcon;
  484.         
  485.     HSetFInfo(spec->vRefNum, spec->parID, spec->name, &info);
  486.     
  487.     return noErr;
  488. }
  489.  
  490. OSErr CopyRsrc(FSSpec * from, FSSpec * to)
  491. {
  492.     OSErr        err;
  493.     short     res;
  494.     short        fromRef;
  495.     short        toRef;
  496.     Handle    copy;
  497.     Ptr        buffer;
  498.     long        len;
  499.     
  500.     copy         = NewHandle(4096);
  501.     buffer     = *copy;
  502.     HLock(copy);
  503.     
  504.     if (err = DoOpenResFile(to, &res))
  505.         goto disposeBuffer;
  506.     
  507.     CloseResFile(res);
  508.     
  509.     if (err = HOpenRF(from->vRefNum, from->parID, from->name, fsRdPerm, &fromRef))
  510.         goto disposeBuffer;
  511.     if (err = HOpenRF(to->vRefNum, to->parID, to->name, fsRdWrPerm, &toRef))
  512.         goto closeFrom;
  513.  
  514.     do {
  515.         len    =    4096;
  516.         
  517.         FSRead(fromRef, &len, buffer);
  518.         FSWrite(toRef, &len, buffer);
  519.     } while (len == 4096);
  520.     
  521.     FSClose(toRef);
  522.     
  523. closeFrom:
  524.     FSClose(fromRef);
  525. disposeBuffer:
  526.     DisposeHandle(copy);
  527.     
  528.     return err;
  529. }
  530.  
  531. OSErr CopyData(FSSpec * from, FSSpec * to)
  532. {
  533.     OSErr        err;
  534.     short        fromRef;
  535.     short        toRef;
  536.     Handle    copy;
  537.     Ptr        buffer;
  538.     long        len;
  539.     
  540.     copy         = NewHandle(4096);
  541.     buffer     = *copy;
  542.     HLock(copy);
  543.     
  544.     if (err = HOpen(from->vRefNum, from->parID, from->name, fsRdPerm, &fromRef))
  545.         goto disposeBuffer;
  546.     if (err = HOpen(to->vRefNum, to->parID, to->name, fsRdWrPerm, &toRef))
  547.         goto closeFrom;
  548.  
  549.     do {
  550.         len    =    4096;
  551.         
  552.         FSRead(fromRef, &len, buffer);
  553.         FSWrite(toRef, &len, buffer);
  554.     } while (len == 4096);
  555.     
  556.     FSClose(toRef);
  557.     
  558. closeFrom:
  559.     FSClose(fromRef);
  560. disposeBuffer:
  561.     DisposeHandle(copy);
  562.     
  563.     return err;
  564. }
  565.  
  566. OSErr MakePackage(FSSpec * spec, short * resFile, DocType type, StringPtr name)
  567. {
  568.     OSErr                    err;
  569.     short                    index;
  570.     short                    packFile;
  571.     ShoppingListHdl    shopping;
  572.  
  573.     BuildSEList();
  574.     
  575.     for (index = 0; index < (*SaveExtensions)->count; ++index)
  576.         if ((*SaveExtensions)->ext[index].id == type)
  577.             break;
  578.     
  579.     if (index == (*SaveExtensions)->count)
  580.         return errAEWrongDataType;
  581.  
  582.     WantsType         = (*SaveExtensions)->ext[index].fType;
  583.     WantsCreator    = (*SaveExtensions)->ext[index].fCreator;
  584.     WantsBundle        = (*SaveExtensions)->ext[index].wantsBundle;
  585.     HasCustomIcon    = (*SaveExtensions)->ext[index].hasCustomIcon;
  586.  
  587.     if (err = DoOpenResFile(spec, resFile))
  588.         return err;
  589.     
  590.     {
  591.         FSSpec *    spec = &(*SaveExtensions)->ext[index].file;
  592.         
  593.         packFile = HOpenResFile(spec->vRefNum, spec->parID, spec->name, fsRdPerm);
  594.     }
  595.     
  596.     if (packFile == -1) {
  597.         err = fnfErr;
  598.         goto done;
  599.     }
  600.     
  601.     if (!(shopping = (ShoppingListHdl) Get1Resource('McPs', SERsrcBase))) {
  602.         err = ResError();
  603.         goto closePackage;
  604.     }
  605.     
  606.     HLock((Handle) shopping);
  607.     err = CopyShoppingList(packFile, *resFile, *shopping, name);
  608.  
  609. closePackage:
  610.     CloseResFile(packFile);
  611. done:    
  612.     if (err)
  613.         CloseResFile(*resFile);
  614.  
  615.     UseResFile(gAppFile);
  616.         
  617.     return err;
  618. }
  619.  
  620. ShoppingList Runtime7Shopping[] =
  621. {
  622.     { 'MrPB', 'BNDL', 128, 128 },
  623.     { 'MrPI', 'ICN#', 128, 128 },
  624.     { 'MrP4', 'icl4', 128, 128 },
  625.     { 'MrP8', 'icl8', 128, 128 },
  626.     { 'MrP#', 'ics#', 128, 128 },
  627.     {          0,    0,     0,     0 }
  628. };
  629.  
  630. OSErr Make7Runtime(FSSpec * spec, short * resFile, StringPtr name)
  631. {
  632.     OSErr        err;
  633.     FSSpec    from;
  634.     
  635.     from.vRefNum    =    gAppVol;
  636.     from.parID        =    gAppDir;
  637.     PLstrcpy(from.name, LMGetCurApName());
  638.  
  639.     if (err = CopyRsrc(&from, spec))
  640.         return err;
  641.         
  642.     if (err = CopyData(&from, spec))
  643.         return err;
  644.         
  645.     if (err = DoOpenResFile(spec, resFile))
  646.         return err;
  647.         
  648.     return CopyShoppingList(gAppFile, *resFile, Runtime7Shopping, name);
  649. }
  650.  
  651. pascal OSErr DoSave(DPtr theDocument, FSSpec theFSSpec, StringPtr name)
  652. {
  653.     OSErr               err;
  654.     short                resFile;
  655.     short                origFile;
  656.     Handle            text    =     (*theDocument->theText)->hText;
  657.     Handle            thePHandle;
  658.     HHandle            theHHandle;
  659.     StringHandle    theAppName;
  660.  
  661.     HDelete(theFSSpec.vRefNum, theFSSpec.parID, theFSSpec.name);
  662.     
  663.     switch (theDocument->type) {
  664.     case kPlainTextDoc:
  665.         {
  666.             short        refNum;
  667.             long        length;
  668.             
  669.             WantsCreator    =    MPAppSig;
  670.             WantsType        =    'TEXT';
  671.             WantsBundle        =    false;
  672.             HasCustomIcon    =    false;
  673.             
  674.             if (err = DoOpenResFile(&theFSSpec, &resFile))
  675.                 return err;
  676.             
  677.             if (err = 
  678.                 HOpenDF(
  679.                     theFSSpec.vRefNum, theFSSpec.parID, theFSSpec.name,
  680.                     fsRdWrPerm, &refNum)
  681.             ) {
  682.                 if (err = DoCreate(theFSSpec))
  683.                     goto closeResource;
  684.                 
  685.                 if (err =
  686.                     HOpenDF(
  687.                         theFSSpec.vRefNum, theFSSpec.parID, theFSSpec.name,
  688.                         fsRdWrPerm, &refNum)
  689.                 ) {
  690.                     FileError((StringPtr) "\perror opening file ", theFSSpec.name);
  691.                     
  692.                     goto closeResource;
  693.                 }
  694.             }
  695.             
  696.             length     = GetHandleSize(text);
  697.             
  698.             HLock(text);
  699.             
  700.             err = FSWrite(refNum, &length, *text);
  701.             
  702.             HUnlock(text);
  703.             FSClose(refNum);
  704.             
  705.             if (err)
  706.                 goto closeResource;
  707.         }
  708.         break;
  709.     default:
  710.         if (err = MakePackage(&theFSSpec, &resFile, theDocument->type, name))
  711.             return err;
  712.         
  713.         goto writeScript;
  714.     case kRuntime7Doc:
  715.         WantsCreator    =    MPRtSig;
  716.         WantsType        =    'APPL';
  717.         WantsBundle        =    true;
  718.         HasCustomIcon    =    false;
  719.  
  720.         if (err = Make7Runtime(&theFSSpec, &resFile, name))
  721.             return err;
  722.         
  723. writeScript:            
  724.         if (err = HandToHand(&text))
  725.             goto closeResource;
  726.         
  727.         UseResFile(resFile);
  728.         
  729.         AddResource(text, 'TEXT', 128, (StringPtr) "\p!");
  730.         if (err = ResError()) {
  731.             DisposeHandle(text);
  732.             
  733.             goto closeResource;
  734.         }
  735.         
  736.         if (err = PtrToHand(&theDocument->type, &text, 4))
  737.             goto closeResource;
  738.         
  739.         AddResource(text, 'MrPL', 128, (StringPtr) "\p");
  740.         if (err = ResError()) {
  741.             DisposeHandle(text);
  742.             
  743.             goto closeResource;
  744.         }
  745.             
  746.         break;
  747.     }
  748.     
  749.     /* write out the printer info */
  750.     if (theDocument->thePrintSetup) {
  751.         thePHandle = (Handle)theDocument->thePrintSetup;
  752.         HandToHand(&thePHandle);
  753.  
  754.         AddResource(thePHandle, 'TFSP', 255, (StringPtr) "\pPrinter Info");
  755.         err = ResError();
  756.         if (err = ResError()) {
  757.             ShowError((StringPtr) "\pAddResource TFSP", err);
  758.             goto closeResource;
  759.         }
  760.     }
  761.  
  762.     theHHandle = (HHandle)NewHandle(sizeof(HeaderRec));
  763.      HLock((Handle)theHHandle);
  764.  
  765.     (*theHHandle)->theRect     = theDocument->theWindow->portRect;
  766.     OffsetRect(
  767.         &(*theHHandle)->theRect,
  768.         -theDocument->theWindow->portBits.bounds.left,
  769.         -theDocument->theWindow->portBits.bounds.top);
  770.         
  771.     GetFontName((*(theDocument->theText))->txFont, (StringPtr) &(*theHHandle)->theFont);
  772.     
  773.     (*theHHandle)->theSize     = (*(theDocument->theText))->txSize;
  774. #ifdef EVIL_USELESS_EDITIONS
  775.     (*theHHandle)->lastID      = theDocument->kind == kDocumentWindow ? theDocument->u.reg.lastID : 0;
  776.     (*theHHandle)->numSections = theDocument->kind == kDocumentWindow ? theDocument->u.reg.numSections : 0;
  777. #endif
  778.  
  779.     HUnlock((Handle)theHHandle);
  780.  
  781.     AddResource((Handle)theHHandle, 'TFSS', 255, (StringPtr) "\pHeader Info");
  782.     if (err = ResError()) {
  783.         ShowError((StringPtr) "\pAddResource- TFSS", err);
  784.         goto closeResource;
  785.     }
  786.  
  787. #ifdef EVIL_USELESS_EDITIONS
  788.     /*if we have any sections, write out the records and resources*/
  789.  
  790.     if (theDocument->kind == kDocumentWindow && theDocument->u.reg.numSections) {
  791.         /*now write out the section records*/
  792.         SaveSections(theDocument);
  793.  
  794.         /*write the latest versions of all editions to their containers*/
  795.  
  796.         WriteAllEditions(theDocument);
  797.     }
  798. #endif
  799.  
  800.     if (theDocument->type == kPlainTextDoc) {
  801.         /*Now put an AppName in for Finder in 7.0*/
  802.     
  803.         theAppName = (StringHandle)NewHandle(8);
  804.         PLstrcpy(*theAppName,(StringPtr) "\pMacPerl");
  805.     
  806.         AddResource((Handle)theAppName, 'STR ', - 16396, (StringPtr) "\pFinder App Info");
  807.         if (err = ResError()) {
  808.             ShowError((StringPtr) "\pAppName", err);
  809.             goto closeResource;
  810.         }
  811.     }
  812.  
  813.     if (theDocument->kind == kDocumentWindow && theDocument->u.reg.everLoaded) {
  814.         /* Copy all resources that need copying */
  815.         
  816.         origFile = 
  817.             HOpenResFile(
  818.                 theDocument->u.reg.origFSSpec.vRefNum,
  819.                 theDocument->u.reg.origFSSpec.parID,
  820.                 theDocument->u.reg.origFSSpec.name,
  821.                 fsRdPerm);
  822.         if (origFile != -1) {
  823.             err = CopySomeResources(origFile, resFile);
  824.                 
  825.             CloseResFile(origFile);
  826.         } 
  827.         /* Otherwise, let's just assume the file had no resource fork */
  828.     }
  829.  
  830. closeResource:
  831.     CloseResFile(resFile);
  832.     UseResFile(gAppFile);
  833.     
  834.     return err;
  835. }
  836.  
  837. void ScanExtensions(OSType type, void (*found)(const FSSpec * spec, CInfoPBRec * info))
  838. {
  839.     short            runs;
  840.     short         index;
  841.     FSSpec        spec;
  842.     CInfoPBRec    info;
  843.     
  844.     spec.vRefNum    =    gAppVol;
  845.     spec.parID        =    gAppDir;
  846.     
  847.     FSpUp(&spec);
  848.     
  849.     for (runs = 0; runs++ < 2; Special2FSSpec(kExtensionFolderType, 0, 0, &spec)) {
  850.         if (FSpDown(&spec, (StringPtr) "\pMacPerl Extensions"))
  851.             continue;
  852.         if (FSpDown(&spec, (StringPtr) "\p"))
  853.             continue;
  854.         for (index = 1; !FSpIndex(&spec, index++); )
  855.             if (!FSpCatInfo(&spec, &info) && info.hFileInfo.ioFlFndrInfo.fdType == type)
  856.                 found(&spec, &info);
  857.     }
  858. }
  859.  
  860. void AddSaveExtension(const FSSpec * spec, CInfoPBRec * info)
  861. {
  862.     short                 res;
  863.     short                    index;
  864.     SEPackageHdl        pack;    
  865.     StringHandle        name;
  866.     SaveExtension *    ext;
  867.     OSType                fType;
  868.     
  869.     res = HOpenResFile(spec->vRefNum, spec->parID, spec->name, fsRdPerm);
  870.     
  871.     if (res == -1)
  872.         return;
  873.         
  874.     if (!(pack = (SEPackageHdl) Get1Resource('McPp', SERsrcBase)))
  875.         goto closeIt;
  876.     
  877.     for (index = 0; index<(*SaveExtensions)->count; ++index)
  878.         if ((*pack)->id == (*SaveExtensions)->ext[index].id)
  879.             goto closeIt;
  880.     
  881.     name    =    (StringHandle) Get1Resource('STR ', SERsrcBase);
  882.     
  883.     SetHandleSize(
  884.         (Handle) SaveExtensions, GetHandleSize((Handle) SaveExtensions) + sizeof(SaveExtension));
  885.     
  886.     ext                         = (*SaveExtensions)->ext + (*SaveExtensions)->count++;
  887.     ext->id                    = (*pack)->id;
  888.     ext->fType                = (*pack)->fType;
  889.     ext->fCreator            = (*pack)->fCreator;
  890.     ext->wantsBundle        = (*pack)->wantsBundle;
  891.     ext->hasCustomIcon    = (*pack)->hasCustomIcon;
  892.     ext->name        = name;
  893.     ext->file         = *spec;
  894.     
  895.     DetachResource((Handle) name);
  896.     
  897.     fType = ext->fType;
  898.     
  899.     for (index = 0; index<MacPerlFileTypeCount; ++index)
  900.         if (fType == (*FileTypeH)[index])
  901.             goto closeIt;
  902.     
  903.     PtrAndHand(&fType, (Handle) FileTypeH, sizeof(OSType));
  904.     
  905.     ++MacPerlFileTypeCount;
  906. closeIt:
  907.     CloseResFile(res);
  908. }
  909.  
  910. pascal void BuildSEList()
  911. {
  912.     if (SaveExtensions)
  913.         return;
  914.     
  915.     SaveExtensions                 = (SEHdl) NewHandle(2);
  916.     (*SaveExtensions)->count     = 0;
  917.     
  918.     PtrToHand("APPLTEXT", (Handle *) &FileTypeH, 8);
  919.     MacPerlFileTypeCount            = 2;
  920.     
  921.     ScanExtensions('McPp', AddSaveExtension);
  922.     
  923.     MoveHHi((Handle) FileTypeH);
  924.     HLock((Handle) FileTypeH);
  925.     
  926.     MacPerlFileTypes                = *FileTypeH;
  927. }
  928.  
  929. pascal Boolean CanSaveAs(DocType type)
  930. {
  931.     short    index;
  932.     
  933.     BuildSEList();
  934.     
  935.     switch (type) {
  936.     case kPlainTextDoc:
  937.     case kRuntime7Doc:
  938.         return true;
  939.     default:
  940.         break;
  941.     }
  942.     
  943.     for (index = 0; index<(*SaveExtensions)->count; ++index)
  944.         if (type == (*SaveExtensions)->ext[index].id)
  945.             return true;
  946.             
  947.     return false;
  948. }
  949.  
  950.  
  951. pascal void AddExtensionsToMenu(MenuHandle menu)
  952. {
  953.     short                index;
  954.     StringHandle    name;
  955.     
  956.     BuildSEList();
  957.     
  958.     for (index = 0; index < (*SaveExtensions)->count; ++index) {
  959.         name = (*SaveExtensions)->ext[index].name;
  960.         
  961.         HLock((Handle) name);
  962.         AppendMenu(menu, (StringPtr) "\px");
  963.         SetMenuItemText(menu, index+ssd_Predef+1, *name);
  964.         HUnlock((Handle) name);
  965.     }
  966. }
  967.  
  968. pascal short Type2Menu(DocType type)
  969. {
  970.     short    index;
  971.  
  972.     BuildSEList();
  973.     
  974.     switch (type) {
  975.     case kPlainTextDoc:
  976.         return 1;
  977.     case kRuntime7Doc:
  978.         return 2;
  979.     default:
  980.         for (index = 0; index < (*SaveExtensions)->count; ++index)
  981.             if ((*SaveExtensions)->ext[index].id == type)
  982.                 return index + ssd_Predef + 1;
  983.     }
  984.     
  985.     /* Should never happen */
  986.     
  987.     return 0;
  988. }
  989.  
  990. pascal DocType Menu2Type(short item)
  991. {
  992.     BuildSEList();
  993.     
  994.     switch (item) {
  995.     case 1:
  996.         return kPlainTextDoc;
  997.     case 2:
  998.         return kRuntime7Doc;
  999.     default:
  1000.         item -= ssd_Predef + 1;
  1001.         
  1002.         if (item < 0 || item >= (*SaveExtensions)->count)
  1003.             return kUnknownDoc;
  1004.         
  1005.         return (*SaveExtensions)->ext[item].id;
  1006.     }
  1007. }
  1008.